// void, Obj This

Building this;
Query qRange, qRange2, qEnemies, qFriends, qFriends2;
ObjList olAll1,olAll2, olDefendersOut1, olDefendersOut2, olOurDefenders, ol_around, olSettUnits;
Unit u, u1, u2;
point p, pos;
rect rc;
bool bNoMore1, bNoMore2;
int i, j, r, new_player;
int old_level_1,old_level_2, end_level_1, end_level_2;
int beg_time_1,beg_time_2,time, interval_1, interval_2; //Set new level time
//constants
int nDefendersMax1,	//how much units from cls1 to spawn at max
	nDefendersMax2,	//how much units  from cls1  to spawn at max
	nDefendersOut1,	//how much units to keep outside if an enemy comes
	nDefendersOut2;	//how much units to keep outside if an enemy comes
//int nFoodIn;
int old_player;

str sDefenderCls1, sDefenderCls2;// defender classes
str raceHero;

Sleep(1420+rand(GetConst("RandTimeStart"))+GetConst("AddTimeStart"));

this = This.AsBuilding();

if (!.IsValid()) return;


if(.IsHeirOf("GOutpost")){
	EnvWriteInt(.settlement, "BuyingFood", 200+rand(100)); // za 10g kupie maks 30f lub min 20f
	EnvWriteInt(.settlement, "SaleFood", 50+rand(50)); // za 10f dostane maks 10g lub min 5g
} else if(.IsHeirOf("TOutpost")){
	EnvWriteInt(.settlement, "BuyingFood", 100+rand(20)); // za 10g kupie maks 12f lub 10f
	EnvWriteInt(.settlement, "SaleFood", 100+rand(100)); // za 10f dostane maks 20g lub min 10g
}

r = 500+rand(400);
j = 1;
while(1){
	
	Sleep(3000);
	j+=1;
	
	if(j > r){
		j = 1;
		if(.IsHeirOf("GOutpost")){
			EnvWriteInt(.settlement, "BuyingFood", 200+rand(100)); // za 10g kupie maks 30f lub min 20f
			EnvWriteInt(.settlement, "SaleFood", 50+rand(50)); // za 10f dostane maks 10g lub min 5g
		} else if(.IsHeirOf("TOutpost")){
			EnvWriteInt(.settlement, "BuyingFood", 100+rand(20)); // za 10g kupie maks 12f lub 10f
			EnvWriteInt(.settlement, "SaleFood", 100+rand(100)); // za 10f dostane maks 20g lub min 10g
		}
	}
	if (.settlement.IsIndependent()) break;
}

if(.race==Gaul){
	sDefenderCls1="GTridentWarrior"; sDefenderCls2="GHorseman";
	
	nDefendersMax1=8;              nDefendersMax2=12;
	
	nDefendersOut1=3;              nDefendersOut2=4;
	
	old_level_1=1;                 old_level_2=1;
	end_level_1=60;                end_level_2=70;
  
	raceHero="GaulHero";

} else if(.race==RepublicanRome){
	sDefenderCls1="RLiberatus"; sDefenderCls2="RPrinciple";
	
	nDefendersMax1=10;        nDefendersMax2=20;
	
	nDefendersOut1=8;         nDefendersOut2=8;
	
	old_level_1=2;                 old_level_2=7;
	end_level_1=90;                end_level_2=100;
	
	raceHero = "RepublicanRomanHero";
	
} else if(.race==Carthage){
	sDefenderCls1="CMaceman"; sDefenderCls2="CWarElephant";
	
	nDefendersMax1=80;       nDefendersMax2=3;
	
	nDefendersOut1=20;       nDefendersOut2=1;
	
	old_level_1=2;                 old_level_2=1;
	end_level_1=90;                end_level_2=40;
	
	raceHero = "CarthaginianHero";
} else if(.race==Iberia){
	sDefenderCls1="ISlinger"; sDefenderCls2="IDefender";
	
	nDefendersMax1=20;       nDefendersMax2=20;
	
	nDefendersOut1=6;        nDefendersOut2=8;
	
	old_level_1=3;                 old_level_2=9;
	end_level_1=90;                end_level_2=90;
	
	raceHero = "IberianHero";
} else if(.race==ImperialRome){
	sDefenderCls1="RLiberatus"; sDefenderCls2="RPrinciple";
	
	nDefendersMax1=10;        nDefendersMax2=20;
	
	nDefendersOut1=8;         nDefendersOut2=8;
	
	old_level_1=2;                 old_level_2=7;
	end_level_1=90;                end_level_2=100;
	
	raceHero = "ImperialRomanHero";
} else if(.race==Britain){
	sDefenderCls1="BHighlander"; sDefenderCls2="BJavelineer";
	
	nDefendersMax1=20;         nDefendersMax2=20;
	
	nDefendersOut1=8;          nDefendersOut2=8;
	
	old_level_1=3;                 old_level_2=3;
	end_level_1=100;               end_level_2=100;
	
	raceHero = "BritonHero";
} else if(.race==Egypt){
	sDefenderCls1="EAnubisWarrior"; sDefenderCls2="EArcherLongBow";
	
	nDefendersMax1=30;            nDefendersMax2=10;
	
	nDefendersOut1=12;            nDefendersOut2=6;
	
	old_level_1=6;                 old_level_2=3;
	end_level_1=120;                end_level_2=100;
	
	raceHero = "EgyptianHero";
} else if(.race==Germany){
	sDefenderCls1="TValkyrie"; sDefenderCls2="TAxeman";
	
	nDefendersMax1=20;        nDefendersMax2=10;
	
	nDefendersOut1=6;         nDefendersOut2=10;
	
	old_level_1=1;                 old_level_2=1;
	end_level_1=100;                end_level_2=120;
	
	raceHero = "GermanHero";
} else {
	sDefenderCls1="GTridentWarrior"; sDefenderCls2="GHorseman";
	
	nDefendersMax1=8;              nDefendersMax2=12;
	
	nDefendersOut1=3;              nDefendersOut2=4;

    old_level_1=1;                 old_level_2=1;
	end_level_1=60;                end_level_2=70; 
	
	raceHero = "GaulHero";
}

rc = GetMapRect();

qRange = ObjsInRange(this, "Unit", .range);
qEnemies = Intersect(qRange, Union(EnemyObjs(.player, "Military"),EnemyObjs(.player, "BaseMage")));
qEnemies = Subtract(qEnemies,EnemyObjs(.player, "Sentry"));
qFriends = Intersect(qRange, ClassPlayerObjs("Military", .player));

qRange = ObjsInRange(this, "Building", .range);
qRange = Intersect(qRange,EnemyObjs(.player, "Catapult"));
qEnemies = Union(qEnemies, qRange);

old_player = .player;

.settlement.SetLoyalty(100); //will not be able to capture it the normal way

//---------------[ main loop ]------------------------------------

if (end_level_1 != old_level_1)
  interval_1 = 9000000 / (end_level_1 - old_level_1);
else
  interval_1 = 0;
  
if (end_level_2 != old_level_2)
  interval_2 = 9000000 / (end_level_2 - old_level_2);
else
  interval_2 = 0;

beg_time_1 = GetTime();
beg_time_2 = beg_time_1;
time = beg_time_1;

 
if (sDefenderCls1!=""){
	for (i=0;i<nDefendersMax1; i+=1)
	{
		if(i == 1){
			Sleep(rand(100)+100);
			u = Place(GetRandomHeroClass(raceHero, .player), .posRH, .player);
			if(u.IsValid){
				int randItem, chance = 9;
				str nameItem;
				
				.settlement.ForceAddUnit(u);
				u.SetFood(16);
				u.SetFeeding( false );
				u.SetLevel(rand(20));
				Sleep(80);
				if(.race==Gaul) chance = 100;
				if(rand(100) < chance){
					randItem = rand(23);

					if(randItem == 0)
							nameItem = "Magic Shoes";
					else if(randItem == 1)
							nameItem = "Battle drums of rage";
					else if(randItem == 2)
							nameItem = "Harp of stamina";
					else if(randItem == 3)
							nameItem = "Sign of the hammer";
					else if(randItem == 4)
							nameItem = "Ghost's skull";
					else if(randItem == 5)
							nameItem = "Wine of vigour";
					else if(randItem == 6)
							nameItem = "Watch Eye II";
					else if(randItem == 7)
							nameItem = "Assassin sword";
					else if(randItem == 8)
							nameItem = "Herb amulet of luck";
					else if(randItem == 9)
							nameItem = "King's Belt";
					else if(randItem == 10)
							nameItem = "Fur gloves of health";
					else if(randItem == 11)
							nameItem = "Finger of death";
					else if(randItem == 12)
							nameItem = "Ash of druid heart";
					else if(randItem == 13)
							nameItem = "Horn of victory";
					else if(randItem == 14)
							nameItem = "Boar teeth";
					else if(randItem == 15)
							nameItem = "Elephant Tusk";
					else if(randItem == 16)
							nameItem = "Gold of resource";
					else if(randItem == 17)
							nameItem = "Food of resource"; 
					else if(randItem == 18)
							nameItem = "Lion's head";
					else if(randItem == 19)
							nameItem = "Healing staff";
					else if(randItem == 20)
							nameItem = "Blue ring";
					else if(randItem == 21)
							nameItem = "Hero speech"; 
					else if(randItem == 22)
							nameItem = "Pouch Gold";
							
					u.AddItem(nameItem);
				}
				Sleep(80);
				if(rand(20) < chance){
					randItem = rand(14);

					if(randItem == 0)
							nameItem = "Apple of feeding";
					else if(randItem == 1)
							nameItem = "Simple boar tooth";
					else if(randItem == 2)
							nameItem = "Watch Eye I";
					else if(randItem == 3)
							nameItem = "Belt of might";
					else if(randItem == 4)
							nameItem = "Rye spikes";
					else if(randItem == 5)
							nameItem = "Snake skin";
					else if(randItem == 6)
							nameItem = "Eagle feather";
					else if(randItem == 7)
							nameItem = "Poison Mushroom";
					else if(randItem == 8)
							nameItem = "Healing herbs";
					else if(randItem == 9)
							nameItem = "Healing water";
					else if(randItem == 10)
							nameItem = "Bloodstone";
					else if(randItem == 11)
							nameItem = "God's Gift";
					else if(randItem == 12)
							nameItem = "Noble Offence";
					else if(randItem == 13)
							nameItem = "Noble Defence";
							
					u.AddItem(nameItem);
				}
				Sleep(80);
				if(rand(30) < chance){
					nameItem = "Apple of feeding";
					u.AddItem(nameItem);
				}
			}
		}
		Sleep(300);
		u1 = Place(sDefenderCls1, .pos, .player);
		if(u1.IsValid){
			.settlement.ForceAddUnit(u1);
			u1.SetFood(20);
			u1.SetFeeding( false );
			u1.SetLevel(old_level_1);
			olAll1.Add(u1);
		}
	}
}
if (sDefenderCls2!="") {
	for (i=0;i<nDefendersMax2; i+=1)
	{
		Sleep(300);
		u2 = Place(sDefenderCls2, .pos, .player);
		if(u2.IsValid){
			.settlement.ForceAddUnit(u2);
			u2.SetFood(20);
			u2.SetFeeding( false );
			u2.SetLevel(old_level_2);
			olAll2.Add(u2);
		}
	}
}
while (1) { 
	olAll1.ClearDead();
	olAll2.ClearDead();
	olDefendersOut1.ClearDead();
	olDefendersOut2.ClearDead();
	
	// clear the units that were commanded from our list
	for (i = olDefendersOut1.count - 1; i >= 0; i -= 1)
		if (olDefendersOut1[i].AsUnit().GetCommanded() || olDefendersOut1[i].AsUnit().player != .player)
			olDefendersOut1.Remove(olDefendersOut1[i]);
	for (i = olDefendersOut2.count - 1; i >= 0; i -= 1)
		if (olDefendersOut2[i].AsUnit().GetCommanded() || olDefendersOut2[i].AsUnit().player != .player)
			olDefendersOut2.Remove(olDefendersOut2[i]);
	//increase level
    time = GetTime();
	olOurDefenders = .settlement.Units();
    if (interval_1>0 && (time - beg_time_1) >= interval_1 && (old_level_1+1)<=end_level_1) // set new level
    {
		Unit u;
		beg_time_1 = time;
		old_level_1+=1;
		for (i = olDefendersOut1.count() - 1; i >= 0; i -= 1) 
		{
			if (!olDefendersOut1[i].IsValid)
				continue;
			u = olDefendersOut1[i];
			if (u.inherentlevel<old_level_1)
				u.SetLevel(old_level_1);
		}
		for (i = olOurDefenders.count() - 1; i >= 0; i -= 1) 
		{
			if (!olOurDefenders[i].IsValid)
				continue;
			u = olOurDefenders[i];
			if (u.IsHeirOf(sDefenderCls1))
				if (u.inherentlevel<old_level_1)
					u.SetLevel(old_level_1);
		}
	}    
	
    if (interval_2>0 &&(time - beg_time_2) >= interval_2 && (old_level_2+1)<=end_level_2) // set new level
    {
		beg_time_2 = time;
		old_level_2+=1;
		for (i = olDefendersOut2.count() - 1; i >= 0; i -= 1) 
		{
			if (!olDefendersOut2[i].IsValid)
				continue;
			u = olDefendersOut2[i];
			if (u.inherentlevel<old_level_2)
				u.SetLevel(old_level_2);
		}
		for (i = olOurDefenders.count() - 1; i >= 0; i -= 1) 
		{
			if (!olOurDefenders[i].IsValid)
				continue;
			u = olOurDefenders[i];
			if (u.IsHeirOf(sDefenderCls2))
				if (u.inherentlevel<old_level_2)
					u.SetLevel(old_level_2);
		}
	}

	if (qEnemies.IsEmpty()) { // no threat around
		// command all that are out to come back in		
		for (i = 0; i < olDefendersOut1.count; i += 1)
			olDefendersOut1[i].SetCommand("enter_tent", this); //force add even though the tent does not allow units inside
		olDefendersOut1.Clear();

		for (i = 0; i < olDefendersOut2.count; i += 1)
			olDefendersOut2[i].SetCommand("enter_tent", this); //force add even though the tent does not allow units inside
		olDefendersOut2.Clear();
		
	} else { 
		// do not allow our teutons to wander too far
		for (i = 0; i < olDefendersOut1.count; i += 1) 
		{
			u = olDefendersOut1[i].AsUnit();
            if(u.IsValid)
			if (.DistTo(u) > .range)  // move to closer random position
			{	
				pos = u.pos - .pos;
				pos.SetLen(.range / 2);
				p = pos + .pos; p.IntoRect(rc);	u.SetCommand("move", p);
				pos.Rot(90);	p = pos + .pos; p.IntoRect(rc);	u.AddCommand(false, "guardpatrol", p);
				pos.Rot(90);	p = pos + .pos; p.IntoRect(rc);	u.AddCommand(false, "guardpatrol", p);
				pos.Rot(90);	p = pos + .pos; p.IntoRect(rc);	u.AddCommand(false, "guardpatrol", p);
				pos.Rot(90);	p = pos + .pos; p.IntoRect(rc);	u.AddCommand(false, "guardpatrol", p);
			}
		}
        
		for (i = 0; i < olDefendersOut2.count; i += 1) 
		{
			u = olDefendersOut2[i].AsUnit();
            if(u.IsValid)
			if (.DistTo(u) > .range)  // move to closer random position
			{	
				pos = u.pos - .pos;
				pos.SetLen(.range / 2);
				p = pos + .pos; p.IntoRect(rc);	u.SetCommand("move", p);
				pos.Rot(90);	p = pos + .pos; p.IntoRect(rc);	u.AddCommand(false, "guardpatrol", p);
				pos.Rot(90);	p = pos + .pos; p.IntoRect(rc);	u.AddCommand(false, "guardpatrol", p);
				pos.Rot(90);	p = pos + .pos; p.IntoRect(rc);	u.AddCommand(false, "guardpatrol", p);
				pos.Rot(90);	p = pos + .pos; p.IntoRect(rc);	u.AddCommand(false, "guardpatrol", p);
			}
		}

		// get out more units if needed
        bNoMore1 = false;
        olDefendersOut1.ClearDead();
		while (olDefendersOut1.count < nDefendersOut1 && .settlement.UnitsCount() > 0 && !bNoMore1) 
		{
			olSettUnits = .settlement.Units();
			for (i=0; i<olSettUnits.count; i+=1)
	        {
				if (olSettUnits[i].IsHeirOf(sDefenderCls1) && olDefendersOut1.count < nDefendersOut1)		
				{ 
					u = olSettUnits[i];
                    if(u.IsValid){
						olDefendersOut1.Add(u);
						pos.Set(0, .range / 2);
						pos.Rot(rand(360));     p = pos + .pos; p.IntoRect(rc); u.SetCommand("guardadvance", p);
						pos.Rot(90);            p = pos + .pos; p.IntoRect(rc); u.AddCommand(false, "guardpatrol", p);
						pos.Rot(90);            p = pos + .pos; p.IntoRect(rc); u.AddCommand(false, "guardpatrol", p);
						pos.Rot(90);            p = pos + .pos; p.IntoRect(rc); u.AddCommand(false, "guardpatrol", p);
						pos.Rot(90);            p = pos + .pos; p.IntoRect(rc); u.AddCommand(false, "guardpatrol", p);
						bNoMore1 = false;
						Sleep(200); 
						break;
                    }
				}
				bNoMore1 = true;
	        }
		}

        bNoMore2 = false;
        olDefendersOut2.ClearDead();
		while (olDefendersOut2.count < nDefendersOut2 && .settlement.UnitsCount() > 0 && !bNoMore2) 
		{

			olSettUnits = .settlement.Units();
			for (i=0; i<olSettUnits.count; i+=1)
	        {
				if (olSettUnits[i].IsHeirOf(sDefenderCls2)&& olDefendersOut2.count < nDefendersOut2)		
				{
					u = olSettUnits[i];
					if(u.IsValid){
						olDefendersOut2.Add(u);
						pos.Set(0, .range / 2);
						pos.Rot(rand(360));     p = pos + .pos; p.IntoRect(rc); u.SetCommand("guardadvance", p);
						pos.Rot(90);            p = pos + .pos; p.IntoRect(rc); u.AddCommand(false, "guardpatrol", p);
						pos.Rot(90);            p = pos + .pos; p.IntoRect(rc); u.AddCommand(false, "guardpatrol", p);
						pos.Rot(90);            p = pos + .pos; p.IntoRect(rc); u.AddCommand(false, "guardpatrol", p);
						pos.Rot(90);            p = pos + .pos; p.IntoRect(rc); u.AddCommand(false, "guardpatrol", p);
						bNoMore2 = false;
						Sleep(200);
						break;
					}
				}
				bNoMore2 = true;
	        }
		}
		
		// handle the capturing
		qRange = ObjsInRange(this, "Unit", .range);
        qRange2 = ObjsInCircle(.pos, 700, "Military"); 
		qEnemies = Intersect(qRange, Union(EnemyObjs(.player, "Military"),EnemyObjs(.player, "BaseMage")));
		qEnemies = Subtract(qEnemies,EnemyObjs(.player, "Sentry"));
		qFriends = Intersect(qRange, ClassPlayerObjs("Military", .player));
        qFriends2 = Intersect(qRange2, ClassPlayerObjs("Military", .player));
        qFriends2 = Subtract(qFriends2, ClassPlayerObjs("Sentry", .player));   
		
		qRange = ObjsInRange(this, "Building", .range);
		qRange = Intersect(qRange,EnemyObjs(.player, "Catapult"));
		qEnemies = Union(qEnemies, qRange);

		olDefendersOut1.ClearDead();		
		olDefendersOut2.ClearDead();		
		olAll1.ClearDead();
		olAll2.ClearDead();
		if (!qEnemies.IsEmpty() && qFriends2.IsEmpty()) 
		{
			if(.settlement.UnitsCount()==0){
			
				qEnemies.GetObjList().ClearDead();
				if (qEnemies.GetObjList().count>0)
				{
					new_player = qEnemies.GetObjList()[rand(qEnemies.GetObjList().count)].player;
					if (new_player>8)
					{
						Sleep(10);
						continue;
					}
					.SetPlayer(new_player);
					//.settlement.SetFood(nFoodIn);
					if (.race==Carthage) // spwan 20 villagers
					{
						for(i=0; i<20; i+=1)
						{
							Sleep(rand(100)+100);
							u1 = Place("CVillager", .pos, new_player);
							if(u1.IsValid) {
								u1.SetFood(u1.maxfood);
								.settlement.ForceAddUnit(u1);
							}
						}
					}
					if (.race==Britain) // spwan 20 BBowmanLongBow
					{
						for(i=0; i<20; i+=1)
						{
							Sleep(rand(100)+100);
							u1 = Place("BBowmanLongBow", .pos, new_player);
							if(u1.IsValid) {
								u1.SetFood(u1.maxfood);
								.settlement.ForceAddUnit(u1);
							}
						}
					}
				}
				  
				// redefine enemies and friends
				qRange = ObjsInRange(this, "Unit", .range);
				qEnemies = Intersect(qRange, Union(EnemyObjs(.player, "Military"),EnemyObjs(.player, "BaseMage")));
				qEnemies = Subtract(qEnemies,EnemyObjs(.player, "Sentry"));
				qFriends = Intersect(qRange, ClassPlayerObjs("Military", .player));
				
				qRange = ObjsInRange(this, "Building", .range);
				qRange = Intersect(qRange,EnemyObjs(.player, "Catapult"));
				qEnemies = Union(qEnemies, qRange);
				if (old_player!=.player)
				{		
					old_player = .player;
					return;
				}
			} else {

				olSettUnits = .settlement.Units();
				for (i=0; i<olSettUnits.count; i+=1){
					u = olSettUnits[i];
					if(u.IsValid){
						pos.Set(0, .range / 2);
						pos.Rot(rand(360));     p = pos + .pos; p.IntoRect(rc); u.SetCommand("guardadvance", p);
						pos.Rot(90);            p = pos + .pos; p.IntoRect(rc); u.AddCommand(false, "guardpatrol", p);
						pos.Rot(90);            p = pos + .pos; p.IntoRect(rc); u.AddCommand(false, "guardpatrol", p);
						pos.Rot(90);            p = pos + .pos; p.IntoRect(rc); u.AddCommand(false, "guardpatrol", p);
						pos.Rot(90);            p = pos + .pos; p.IntoRect(rc); u.AddCommand(false, "guardpatrol", p);
						Sleep(200);
					}
				}
			}
			   
		}
		if (old_player != .player) {
			// redefine enemies and friends
			qRange = ObjsInRange(this, "Unit", .range);
			qEnemies = Intersect(qRange, Union(EnemyObjs(.player, "Military"),EnemyObjs(.player, "BaseMage")));
			qEnemies = Subtract(qEnemies,EnemyObjs(.player, "Sentry"));
			qFriends = Intersect(qRange, ClassPlayerObjs("Military", .player));
			
			qRange = ObjsInRange(this, "Building", .range);
			qRange = Intersect(qRange,EnemyObjs(.player, "Catapult"));
			qEnemies = Union(qEnemies, qRange);
			old_player = .player;
			
			return;
		}
	}
	Sleep(1100);
}
